package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"iris_product/common"
	"iris_product/datamodels"
	"iris_product/encrypt"
	"log"
	"net/http"
	"strconv"
	"sync"
)

func Auth(w http.ResponseWriter, r *http.Request) error {
	// 执行验证逻辑
	fmt.Println("执行验证")
	err := CheckUserInfo(r)
	if err != nil {
		return err
	}

	return nil
}

func Check(w http.ResponseWriter,r *http.Request)  {
	fmt.Println("执行真正的业务逻辑")
}

var hashConsistent *common.Consistent

var hostArray = []string{"127.0.0.1:8082","127.0.0.1:8083"}

var localHost = "127.0.0.1:8082"

// 用来存放控制信息
type AccessControl struct {
	sourcesArray map[int]interface{}
	*sync.RWMutex
}

// 创建全局变量
var accessControl = &AccessControl{
	sourcesArray: make(map[int]interface{}),
	RWMutex:      &sync.RWMutex{},
}

// 获取制定的用户数据
func (m *AccessControl) GetNewRecord(uid int) interface{} {
	m.RLock()
	defer m.RUnlock()
	data := m.sourcesArray[uid]
	return data
}

// 设置记录
func (m *AccessControl) SetNewRecord(uid int) {
	m.Lock()
	defer m.Unlock()
	m.sourcesArray[uid] = "hello word"
}

func (m *AccessControl) GetDistributeRight(req *http.Request) bool {
	// 获取用户UID
	uidCookie,err := req.Cookie("uid")
	if err != nil {
		return false
	}
	// 采用一致性hash算法,根据用户ID,判断获取具体机器
	hostRequest,err := hashConsistent.Get(uidCookie.Value)
	if err != nil {
		log.Printf("采用一致性hash算法,根据用户ID,判断获取具体机器失败:" + err.Error())
		return false
	}
	// 判断是否为本机
	if hostRequest == localHost {
		// 执行本机数据读取和校验
		return m.GetDataFromMap(uidCookie.Value)
	} else {
		// 不是本机,调用外机接口访问数据
		return GetDataFromOtherMap(hostRequest,req)
	}

}

// 获取本机map, 并且处理业务逻辑,返回的结果来兴为bool类型
func (m *AccessControl) GetDataFromMap(uid string) (isOk bool) {
	// uid 转为int
	uidInt,err := strconv.Atoi(uid)
	if err != nil {
		return false
	}
	data := m.GetNewRecord(uidInt)
	if data != nil {
		return true
	}
	return false
}

// 获取其他节点处理结果
func  GetDataFromOtherMap(host string,r *http.Request) bool  {
	// 获取uid
	uidCookie,err := r.Cookie("uid")
	if err != nil {
		return false
	}
	signCookie,err := r.Cookie("sign")
	if err != nil {
		return false
	}
	// 模拟接口访问
	client := &http.Client{}
	req,err := http.NewRequest("GET","http://" + host +"/access?uid="+uidCookie.Value + "&sign="+signCookie.Value,nil)
	if err != nil {
		log.Printf("构建分布式验证节点处理失败:" + err.Error())
		return false
	}
	// 设置cookie
	req.AddCookie(&http.Cookie{Name: "uid",Value: uidCookie.Value,Path: "/"})
	req.AddCookie(&http.Cookie{Name: "sign",Value: signCookie.Value,Path: "/"})
	resp,err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		log.Printf("获取其他节点接口失败,节点地址为:"+host+" 失败信息为:" + err.Error())
		return false
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false
	}
	// 判断状态
	if resp.StatusCode == 200 {
		if string(body) == "true" {
			return true
		} else  {
			log.Printf("请求返回状态失败:")
			return false
		}
	}
	return false
}


func main() {

	// 负载均衡器设置
	// 采用一致性hash算法
	hashConsistent = common.NewConsistent()
	// 采用一致性hash算法,添加节点
	for _, v := range hostArray {
		hashConsistent.Add(v)
	}
	fmt.Println("当前hash环节点为:" + strconv.Itoa(len(hashConsistent.Circle)))


	// 1,过滤器
	filter := common.NewFilter()
	filter.RegisterFilterUri("/check",Auth)
	// 启动服务
	http.HandleFunc("/check",filter.Handler(Check))
	http.ListenAndServe(":8082",nil)
}

// 验证用户登陆
func CheckUserInfo(r *http.Request) (err error) {
	uidCookie,err  := r.Cookie("uid")
	if err != nil {
		return err
	}
	uidStr := uidCookie.Value
	if uidStr == "" {
		return errors.New("没有获取到uid的值")
	}
	uid,_ := strconv.ParseInt(uidStr,10,64)
	signCookie,err  := r.Cookie("sign")
	if err != nil {
		return err
	}
	sign := signCookie.Value

	deSign, err := encrypt.DePwdCode(sign)
	if err != nil {
		fmt.Println(err.Error())
		return  errors.New("秘钥被篡改")
	}
	fmt.Println("解密出的字符为:" + string(deSign))
	user := &datamodels.User{}
	err = json.Unmarshal(deSign, user)
	if err != nil {
		fmt.Println(err.Error())
		return errors.New("秘钥被篡改2")
	}
	if user.ID != uid {
		return errors.New("uid对比失败")
	}
	//fmt.Println(user)
	//fmt.Println(string(deSign))

	return nil
}